package com.atguigu.gmall.task.config;

import com.alibaba.fastjson.JSONObject;
import com.atguigu.gmall.task.entity.GmallCorrelationData;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.connection.CorrelationData;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;

/**
 * @author: 李旭
 * @create: 2021-07-24 11:48
 *
 *   交换机应答
 *   队列应答的
 *     实现类
 **/
@Component
@Slf4j
public class MQProducerAckConfig implements RabbitTemplate.ConfirmCallback,
                                           RabbitTemplate.ReturnCallback{
    @Autowired
    private RabbitTemplate rabbitTemplate;//获取出来
    @Autowired
    private RedisTemplate redisTemplate;
    //后置注解
    @PostConstruct
    public void mqProducerAckConfig(){
        rabbitTemplate.setConfirmCallback(this);
        rabbitTemplate.setReturnCallback(this);
    }

    //交换机应答时 执行的方法   成功或失败都应答
    @Override
    public void confirm(CorrelationData correlationData, boolean ack, String cause) {
        if(ack){
            //成功之后应答
            log.info("交换机成功应答:原因:{}",cause);
        }else{
            //失败之后应答
            log.error("交换机失败应答:原因:{}",cause);
            //重新发送   重发次数 3次  打印 日志
            retrySendMessage(correlationData);
        }

    }
    //重新发送
    private void retrySendMessage(CorrelationData correlationData) {
        GmallCorrelationData gmallCorrelationData = (GmallCorrelationData)correlationData;
        //只重新发送 3次
        int retryCount = gmallCorrelationData.getRetryCount();
        if(retryCount < 3){
            retryCount++;
            gmallCorrelationData.setRetryCount(retryCount);
            log.error("重新发送:次数{}",retryCount);

            //更新Redis
            //保存到缓存中
            redisTemplate.opsForHash().put("gmallCorrelationData",gmallCorrelationData.getId(),
                    JSONObject.toJSONString(gmallCorrelationData));//json转换异常
            //发送消息
            rabbitTemplate.convertAndSend(gmallCorrelationData.getExchange(),
                    gmallCorrelationData.getRoutingKey(),gmallCorrelationData.getMessage(),

                    gmallCorrelationData);
        }
    }
    //队列应答时 执行方法   只有失败了才应答
    @Override
    public void returnedMessage(Message message,
                                int replyCode,
                                String replyText,
                                String exchange,
                                String routingKey) {

        log.error("队列应答失败:原因:{},{}",replyCode,replyText);

        //缓存 Redis 从Redis中获取 GmallCorrelationData  Redis就是外力
        // 1:发消息的时候 就要把 "gmallCorrelationData",uuid  GmallCorrelationData 保存到缓存中
        // 2:像下面一样获取
        String uuid = message.getMessageProperties().
                getHeader("spring_returned_message_correlation");

        // H:"gmallCorrelationData"  HK:uuid   HV:GmallCorrelationData
        GmallCorrelationData gmallCorrelationData = JSONObject.parseObject((String)
                        redisTemplate.opsForHash().get("gmallCorrelationData", uuid)
                , GmallCorrelationData.class);
        //判断 是否为延迟消息
        if(!gmallCorrelationData.isDelay()){
            //重新发送
            retrySendMessage(gmallCorrelationData);
        }else{
            log.info("是延迟消息，不用重新发送:{}",JSONObject.toJSONString(gmallCorrelationData));
        }

    }
}
